package com.zhangtao.demo.controlleradvice;

import java.util.Optional;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import com.zhangtao.demo.common.enums.ResultStatus;
import com.zhangtao.demo.common.util.ThrowableUtil;
import com.zhangtao.demo.common.vo.JsonResponseEntity;

public class ControllerAdvice extends ResponseEntityExceptionHandler {
	private static final Logger LOG = LogManager.getLogger(ControllerAdvice.class);
	private static final String CAUSE_DETAILMSG_EMPTYSTRING = "EMPTYSTRING";

	@ExceptionHandler({ RuntimeException.class })
	public final ResponseEntity<Object> handleRuntimeException(Exception ex, WebRequest request) {
		HttpHeaders headers = new HttpHeaders();
		HttpStatus status = HttpStatus.OK;
		LOG.error("RuntimeException occured on " + request.toString() + ",msg : "
				+ ThrowableUtil.getErrorInfoFromThrowable(ex));
		JsonResponseEntity<Object> rep = JsonResponseEntity.newJsonResult(ResultStatus.SYSTEM_EXP);
		return new ResponseEntity<Object>(rep, headers, status);
	}

	@Override
	protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers,
			HttpStatus status, WebRequest request) {
		LOG.error("ExceptionInternal occured on " + request.toString() + ",msg : "
				+ ThrowableUtil.getErrorInfoFromThrowable(ex));
		status = HttpStatus.OK;
		JsonResponseEntity<Object> rep = JsonResponseEntity.newJsonResult(ResultStatus.SYSTEM_EXP, ex.getMessage());
		return new ResponseEntity<Object>(rep, headers, status);
	}

	/**
	 * 请求方式异常捕捉
	 */
	@Override
	protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex,
			HttpHeaders headers, HttpStatus status, WebRequest request) {
		LOG.error("HttpRequestMethodNotSupportedException occured on " + request.toString() + ",msg : "
				+ ThrowableUtil.getErrorInfoFromThrowable(ex));
		status = HttpStatus.OK;
		JsonResponseEntity<Object> rep = JsonResponseEntity.newJsonResultWithMsg(ResultStatus.SYSTEM_EXP,
				ex.getMessage());
		return new ResponseEntity<Object>(rep, headers, status);
	}

	/**
	 * 请求参数异常捕捉：参数类型不正确
	 */
	@Override
	protected ResponseEntity<Object> handleTypeMismatch(TypeMismatchException ex, HttpHeaders headers,
			HttpStatus status, WebRequest request) {
		LOG.error("TypeMismatchException occured on " + request.toString() + ",msg : "
				+ ThrowableUtil.getErrorInfoFromThrowable(ex));
		status = HttpStatus.OK;
		JsonResponseEntity<Object> rep = JsonResponseEntity.newJsonResultWithMsg(ResultStatus.BIZ_FAILURE,
				ex.getLocalizedMessage());
		String causeDetail = Optional.ofNullable(ex).map(ev -> ev.getCause()).map(evc -> evc.getMessage()).get();
		String formatteMsg = StringUtils.trimToEmpty(causeDetail).replaceAll(" ", "");
		if (StringUtils.equalsIgnoreCase(formatteMsg, CAUSE_DETAILMSG_EMPTYSTRING)) {
			rep = JsonResponseEntity.newJsonResult(ResultStatus.PARAM_EXP);
		}
		return new ResponseEntity<Object>(rep, headers, status);
	}

	/**
	 * 请求参数异常捕捉：缺少请求参数
	 */
	@Override
	protected ResponseEntity<Object> handleMissingServletRequestParameter(MissingServletRequestParameterException ex,
			HttpHeaders headers, HttpStatus status, WebRequest request) {
		LOG.error("MissingServletRequestParameterException occured on " + request.toString() + ",msg : "
				+ ThrowableUtil.getErrorInfoFromThrowable(ex));
		status = HttpStatus.OK;
		JsonResponseEntity<Object> rep = JsonResponseEntity.newJsonResult(ResultStatus.PARAM_EXP);
		return new ResponseEntity<Object>(rep, headers, status);
	}
}
